1 module hip.graphics.g2d.renderer2d;
2 
3 version(Have_bindbc_lua) version = HipremeEngineLua;
4 
5 import hip.graphics.g2d.spritebatch;
6 import hip.graphics.g2d.tilemap;
7 import hip.graphics.g2d.geometrybatch;
8 import hip.graphics.orthocamera;
9 import hip.hiprenderer;
10 import hip.bind.interpreters;
11 public import hip.api.graphics.color;
12 public import hip.graphics.g2d.textrenderer;
13 public import hip.api.renderer.viewport;
14 
15 public import hip.api.data.font;
16 
17 package __gshared
18 {
19     IHipTexture defaultTexture;
20     HipSpriteBatch spBatch;
21     GeometryBatch geoBatch;
22     HipTextRenderer textBatch;
23     HipOrthoCamera camera;
24     Viewport viewport;
25     HipTextRenderer textRenderer;
26     IHipBatch lastBatch;
27     bool autoUpdateCameraAndViewport;
28     float sharedDepth = 0;
29 }
30 
31 void manageBatchChange(IHipBatch newBatch)
32 {
33     if(lastBatch !is null && lastBatch !is newBatch)
34     {
35         sharedDepth+= 0.1;
36         lastBatch.draw();
37 
38         if(newBatch !is null)
39             newBatch.setCurrentDepth(sharedDepth);
40     }
41     lastBatch = newBatch;
42 }
43 
44 
45 import hip.console.log;
46 void initialize(HipInterpreterEntry entry = HipInterpreterEntry.init, bool shouldAutoUpdateCameraAndViewport = true)
47 {
48     autoUpdateCameraAndViewport = shouldAutoUpdateCameraAndViewport;
49     hiplog("2D Renderer: Initializing viewport");
50     viewport = new Viewport(0, 0, HipRenderer.width, HipRenderer.height);
51     viewport.setWorldSize(HipRenderer.width, HipRenderer.height);
52     viewport.setType(ViewportType.fit, HipRenderer.width, HipRenderer.height);
53     HipRenderer.setViewport(viewport);
54     hiplog("2D Renderer: Initializing camera");
55     camera = new HipOrthoCamera();
56     camera.setSize(viewport.worldWidth, viewport.worldHeight);
57 
58     hiplog("2D Renderer: Initializing text renderer");
59     textBatch = new HipTextRenderer(camera);
60     hiplog("2D Renderer: Initializing geometrybatch");
61     geoBatch = new GeometryBatch(camera);
62     hiplog("2D Renderer: Initializing spritebatch");
63     spBatch = new HipSpriteBatch(camera);
64     // setGeometryColor(HipColor.white);
65 
66 
67     version(HipremeEngineLua)
68     {
69         hiplog("2D Renderer: sending lua functions");
70         if(entry != HipInterpreterEntry.init)
71         {
72             sendInterpreterFunc!(setGeometryColor)(entry.intepreter);
73             sendInterpreterFunc!(drawPixel)(entry.intepreter);
74             sendInterpreterFunc!(drawRectangle)(entry.intepreter);
75             sendInterpreterFunc!(drawTriangle)(entry.intepreter);
76             sendInterpreterFunc!(fillRectangle)(entry.intepreter);
77             sendInterpreterFunc!(fillEllipse)(entry.intepreter);
78             sendInterpreterFunc!(drawEllipse)(entry.intepreter);
79             sendInterpreterFunc!(fillTriangle)(entry.intepreter);
80             sendInterpreterFunc!(drawLine)(entry.intepreter);
81             sendInterpreterFunc!(drawQuadraticBezierLine)(entry.intepreter);
82             // sendInterpreterFunc!(drawText)(entry.intepreter); not supported yet
83         }
84     }
85 
86 }
87 
88 /**
89 *   This resizes both the 2D renderer viewport and its Orthographic Camera, maintaining always the
90 *   correct aspect ratio
91 */
92 void resizeRenderer2D(uint width, uint height)
93 {
94     if(autoUpdateCameraAndViewport)
95     {
96         if(viewport !is null && HipRenderer.getCurrentViewport() == viewport)
97             HipRenderer.setViewport(viewport);
98         if(camera !is null)
99             camera.setSize(viewport.worldWidth, viewport.worldHeight);
100     }
101 }
102 
103 //TODO: Find a way to remove export from release
104 export extern(System):
105 
106 
107 int[2] getWindowSize(){return [HipRenderer.width, HipRenderer.height];}
108 
109 void setWindowSize(uint width, uint height)
110 {
111     HipRenderer.setWindowSize(width, height);
112     HipRenderer.setViewport(viewport);
113     camera.setSize(cast(int)viewport.worldWidth,cast(int)viewport.worldHeight);
114 }
115 void setCameraSize(uint width, uint height){camera.setSize(width, height);}
116 void setViewport(Viewport v)
117 {
118     HipRenderer.setViewport(v);
119 }
120 void setStencilTestingEnabled(bool bEnable)
121 {
122     manageBatchChange(null);
123     HipRenderer.setStencilTestingEnabled(bEnable);
124 }
125 void setStencilTestingMask(uint mask)
126 {
127     manageBatchChange(null);
128     HipRenderer.setStencilTestingMask(mask);
129 }
130 void setRendererColorMask(ubyte r, ubyte g, ubyte b, ubyte a)
131 {
132     manageBatchChange(null);
133     HipRenderer.setColorMask(r,g,b,a);
134 }
135 void setStencilTestingFunction(HipStencilTestingFunction passFunc, uint reference, uint mask)
136 {
137     manageBatchChange(null);
138     HipRenderer.setStencilTestingFunction(passFunc, reference, mask);
139 }
140 void setStencilOperation(HipStencilOperation stencilFail, HipStencilOperation depthFail, HipStencilOperation stencilAndDephPass)
141 {
142     manageBatchChange(null);
143     HipRenderer.setStencilOperation(stencilFail, depthFail, stencilAndDephPass);
144 }
145 Viewport getCurrentViewport()
146 {
147     return HipRenderer.getCurrentViewport();
148 }
149 
150 void setRendererErrorCheckingEnabled(bool enable)
151 {
152     HipRenderer.setErrorCheckingEnabled(enable);
153 }
154 void setGeometryColor(const HipColor color){geoBatch.setColor(color);}
155 void drawPixel(int x, int y, HipColor color = HipColor.no)
156 {
157     manageBatchChange(geoBatch);
158     geoBatch.drawPixel(x, y,color);
159 }
160 void drawRectangle(int x, int y, int w, int h, HipColor color = HipColor.no)
161 {
162     manageBatchChange(geoBatch);
163     geoBatch.drawRectangle(x,y,w,h,color);
164 }
165 void drawTriangle(int x1, int y1, int x2, int y2, int x3, int y3, HipColor color = HipColor.no)
166 {
167     manageBatchChange(geoBatch);
168     geoBatch.drawTriangle(x1,y1,x2,y2,x3,y3,color);
169 }
170 void drawEllipse(int x, int y, int radiusW, int radiusH, int degrees = 360, HipColor color = HipColor.no, int precision = 24)
171 {
172     manageBatchChange(geoBatch);
173     geoBatch.drawEllipse(x,y,radiusW,radiusH,degrees,color,precision);
174 }
175 void drawLine(int x1, int y1, int x2, int y2, HipColor color = HipColor.no)
176 {
177     manageBatchChange(geoBatch);
178     geoBatch.drawLine(x1,y1,x2,y2,color);
179 }
180 void drawQuadraticBezierLine(int x0, int y0, int x1, int y1, int x2, int y2, int precision=24, HipColor color = HipColor.no)
181 {
182     manageBatchChange(geoBatch);
183     geoBatch.drawQuadraticBezierLine(x0,y0,x1,y1,x2,y2,precision,color);
184 }
185 void fillRectangle(int x, int y, int w, int h, HipColor color = HipColor.no)
186 {
187     manageBatchChange(geoBatch);
188     geoBatch.fillRectangle(x,y,w,h,color);
189 }
190 void fillRoundRect(int x, int y, int w, int h, int radius = 4, HipColor color = HipColor.no, int precision = 16)
191 {
192     manageBatchChange(geoBatch);
193     geoBatch.fillRoundRect(x,y,w,h,radius, color, precision);
194 }
195 void fillEllipse(int x, int y, int radiusW, int radiusH = -1, int degrees = 360, HipColor color = HipColor.no, int precision = 24)
196 {
197     manageBatchChange(geoBatch);
198     geoBatch.fillEllipse(x,y,radiusW,radiusH,degrees,color,precision);
199 }
200 void fillTriangle(int x1, int y1, int x2,  int y2, int x3, int y3, HipColor color = HipColor.no)
201 {
202     manageBatchChange(geoBatch);
203     geoBatch.fillTriangle(x1,y1,x2,y2,x3,y3,color);
204 }
205 
206 void drawSprite(IHipTexture texture, ubyte[] vertices)
207 {
208     manageBatchChange(spBatch);
209     spBatch.draw(texture, vertices);
210 }
211 void drawRegion(IHipTextureRegion reg, int x, int y, int z = 0, const HipColor color = HipColor.white, float scaleX = 1, float scaleY = 1, float rotation = 0)
212 {
213     manageBatchChange(spBatch);
214     spBatch.draw(reg, x, y, z, color, scaleX, scaleY, rotation);
215 }
216 void drawMap(IHipTilemap map)
217 {
218     manageBatchChange(spBatch);
219     map.render(spBatch, false);
220 }
221 
222 void drawTexture(IHipTexture texture, int x, int y, int z = 0, const HipColor color = HipColor.white, float scaleX = 1, float scaleY = 1, float rotation = 0)
223 {
224     manageBatchChange(spBatch);
225     spBatch.draw(texture, x, y, z, color, scaleX, scaleY, rotation);
226 }
227 
228 
229 public import hip.util.data_structures : Array2D, Array2D_GC;
230 Array2D_GC!IHipTextureRegion cropSpritesheet(
231     IHipTexture t,
232     uint frameWidth, uint frameHeight,
233     uint width, uint height,
234     uint offsetX, uint offsetY,
235     uint offsetXPerFrame, uint offsetYPerFrame
236 )
237 {
238     import hip.assets.texture;
239     import hip.util.lifetime;
240     return cast(typeof(return))hipSaveRef(HipTextureRegion.cropSpritesheet(t, 
241         frameWidth, frameHeight, 
242         width, height, 
243         offsetX, offsetY, 
244         offsetXPerFrame, offsetYPerFrame
245     ).toGC());
246 }
247 
248 void setFont(IHipFont font)
249 {
250     import hip.global.gamedef;
251     if(font is null)
252         textBatch.setFont(cast(IHipFont)HipDefaultAssets.font);
253     else
254         textBatch.setFont(font);
255 }
256 
257 void setTextColor(HipColor color)
258 {
259     manageBatchChange(textBatch);
260     textBatch.setColor(color);
261 }
262 void drawText(string text, int x, int y, float scale = 1.0f, HipColor color = HipColor.white, HipTextAlign align_ = HipTextAlign.centerLeft,
263 Size bounds = Size.init, bool wordWrap = false)
264 {
265     manageBatchChange(textBatch);
266     textBatch.setColor(color);
267     textBatch.draw(text, x, y, scale, align_, bounds, wordWrap);
268 }
269 
270 void drawTextVertices(void[] vertices, IHipFont font)
271 {
272     manageBatchChange(textBatch);
273     textBatch.addVertices(vertices, font);
274 }
275 
276 Array2D_GC!IHipTextureRegion cropSpritesheetRowsAndColumns(IHipTexture t, uint rows, uint columns)
277 {
278     uint frameWidth = t.getWidth() / columns;
279     uint frameHeight = t.getHeight() / rows;
280         return cropSpritesheet(t,frameWidth,frameHeight, t.getWidth, t.getHeight, 0, 0, 0, 0);
281 }
282 
283 void finishRender2D()
284 {
285     if(geoBatch) geoBatch.flush();
286     if(spBatch) spBatch.flush();
287     if(textBatch) textBatch.flush();
288     lastBatch = null;
289     sharedDepth = 0;
290     if(geoBatch) geoBatch.setCurrentDepth(0);
291     if(spBatch) spBatch.setCurrentDepth(0);
292     if(textBatch) textBatch.setCurrentDepth(0);
293 }
294 
295 void drawGCStats(int x = 0, int y = -1)
296 {
297     import hip.graphics.g2d.profiling;
298     hip.graphics.g2d.profiling.drawGCStats(x, y);
299 }
300 
301 void drawTimings(int x = -1, int y = 0, bool clearTimings = false)
302 {
303     import hip.graphics.g2d.profiling;
304     hip.graphics.g2d.profiling.drawTimings(x, y, clearTimings);
305 }
306 
307 version(Standalone)
308 {
309     public import exportd;
310 }